<template>
  <Mapbox :mapOnLoadCB="mapOnLoadCB"></Mapbox>
  <div class='map-overlay'>
    <fieldset>
      <input id='feature-filter' type='text' placeholder='Filter results by name'/>
    </fieldset>
    <div id='feature-listing' class='listing'></div>
  </div>
</template>

<script>
import {ref} from "vue"
import Mapbox from "@/components/common/Mapbox.component.vue"
import MapboxCommonService from "@/service/map/MapboxCommonService"

export default {
  name: "SwitchFilter.component",
  components: {Mapbox},
  setup() {

    let mapStore = ref({});
    let mapOnLoadCB = (map) => {
      mapStore.value = map;
      MapboxCommonService.setCZBP(map, [-98, 38.88], 3)
      map.setMinZoom(1)
      map.setMaxZoom(5)

      // 在 map view 中筛选要素，移动地图以查询矢量切片图层中的可视要素，并通过输入文本筛选要素。
      // Holds visible airport features for filtering
      let airports = [];

      // Create a popup, but don't add it to the map yet.
      let popup = new mapboxgl.Popup({
        closeButton: false
      });

      let filterEl = document.getElementById('feature-filter');
      let listingEl = document.getElementById('feature-listing');

      const renderListings = (features) => {
        // Clear any existing listings
        listingEl.innerHTML = '';
        if (features.length) {
          features.forEach((feature) => {
            let prop = feature.properties;
            let item = document.createElement('a');
            item.href = prop.wikipedia;
            item.target = '_blank';
            item.textContent = prop.name + ' (' + prop.abbrev + ')';
            item.addEventListener('mouseover', () => {
              // Highlight corresponding feature on the map
              popup.setLngLat(feature.geometry.coordinates)
                  .setText(feature.properties.name + ' (' + feature.properties.abbrev + ')')
                  .addTo(map);
            });
            listingEl.appendChild(item);
          });

          // Show the filter input
          filterEl.parentNode.style.display = 'block';
        } else {
          let empty = document.createElement('p');
          empty.textContent = 'Drag the map to populate results';
          listingEl.appendChild(empty);

          // Hide the filter input
          filterEl.parentNode.style.display = 'none';

          // remove features filter
          map.setFilter('airport', ['has', 'abbrev']);
        }
      }

      const normalize = (string) => {
        return string.trim().toLowerCase();
      }

      const getUniqueFeatures = (array, comparatorProperty) => {
        let existingFeatureKeys = {};
        // Because features come from tiled vector data, feature geometries may be split
        // or duplicated across tile boundaries and, as a result, features may appear
        // multiple times in query results.
        return array.filter((el) => {
          if (existingFeatureKeys[el.properties[comparatorProperty]]) {
            return false;
          } else {
            existingFeatureKeys[el.properties[comparatorProperty]] = true;
            return true;
          }
        });
      }
      map.addLayer({
        "id": "airport",
        "source": {
          "type": "vector",
          "url": `${window.location.origin}/mapbox-test/libs/mapbox/assets/mapbox.04w69w5j.json`
        },
        "source-layer": "ne_10m_airports",
        "type": "symbol",
        "layout": {
          "icon-image": "airport-15",
          "icon-padding": 0,
          "icon-allow-overlap": true
        }
      });

      map.on('moveend', () => {
        let features = map.queryRenderedFeatures({layers: ['airport']});

        if (features) {
          let uniqueFeatures = getUniqueFeatures(features, "iata_code");
          // Populate features for the listing overlay.
          renderListings(uniqueFeatures);

          // Clear the input container
          filterEl.value = '';

          // Store the current features in sn `airports` letiable to
          // later use for filtering on `keyup`.
          airports = uniqueFeatures;
        }
      });

      map.on('mousemove', 'airport', (e) => {
        // Change the cursor style as a UI indicator.
        map.getCanvas().style.cursor = 'pointer';

        // Populate the popup and set its coordinates based on the feature.
        let feature = e.features[0];
        popup.setLngLat(feature.geometry.coordinates)
            .setText(feature.properties.name + ' (' + feature.properties.abbrev + ')')
            .addTo(map);
      });

      map.on('mouseleave', 'airport', () => {
        map.getCanvas().style.cursor = '';
        popup.remove();
      });

      filterEl.addEventListener('keyup', (e) => {
        let value = normalize(e.target.value);

        // Filter visible features that don't match the input value.
        let filtered = airports.filter((feature) => {
          let name = normalize(feature.properties.name);
          let code = normalize(feature.properties.abbrev);
          return name.indexOf(value) > -1 || code.indexOf(value) > -1;
        });

        // Populate the sidebar with filtered results
        renderListings(filtered);

        // Set the filter to populate features into the layer.
        map.setFilter('airport', ['match', ['get', 'abbrev'], filtered.map((feature) => {
          return feature.properties.abbrev;
        }), true, false]);
      });

      // Call this function on initialization
      // passing an empty array to render an empty state
      renderListings([]);
    };

    return {
      mapOnLoadCB
    }
  }
}
</script>

<style scoped lang="scss">
.map-overlay {
  position: absolute;
  width: 20%;
  top: 0;
  bottom: 0;
  left: 0;
  font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
  background-color: #fff;
  max-height: 100%;
  overflow: hidden;

  fieldset {
    display: none;
    background: #ddd;
    border: none;
    padding: 10px;
    margin: 0;
  }

  input {
    display: block;
    border: none;
    width: 100%;
    border-radius: 3px;
    padding: 10px;
    margin: 0;
  }

  .listing {
    overflow: auto;
    max-height: 100%;

    & > * {
      display: block;
      padding: 5px 10px;
      margin: 0;
    }

    a {
      border-bottom: 1px solid rgba(0, 0, 0, 0.1);
      color: #404;
      text-decoration: none;
    }

    &:last-child {
      border: none;
    }

    &:hover {
      background: #f0f0f0;
    }
  }
}
</style>